﻿using Aliphant.Common.Caches;
using Aliphant.Tool.ExcelToJson.Helpers;
using Aliphant.Tool.ExcelToJson.Interface;
using Aliphant.Tool.ExcelToJson.Models;
using System.Data;
using System.Dynamic;

namespace Aliphant.Tool.ExcelToJson.Impl
{
    internal class DataConverter : IConverter
    {
        IDictionary<string, DataTable> _dtList = new Dictionary<string, DataTable>();
        IDictionary<string, dynamic[]> _dynamicTable = new Dictionary<string, dynamic[]>();
        dynamic? root;

        public DataConverter()
        {
            UpdateDataTableList();
        }

        #region 接口实现

        /// <summary>
        /// 解析
        /// </summary>
        public void OnAnalysis(string filePath)
        {
            try
            {
                UpdateDataTableList();
                ConvertTable();
                SaveToJson(filePath);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
            finally
            {

            }
        }

        #endregion

        private void UpdateDataTableList()
        {
            var dtList = PublicCache.Instance.Get(Constants.CacheDataTable) as IDictionary<string, DataTable>;

            _dtList = dtList != null ? dtList : new Dictionary<string, DataTable>();
        }

        /// <summary>
        /// 转换DataTable
        /// </summary>
        private void ConvertTable()
        {
            foreach (var item in _dtList)
            {
                if (item.Key.StartsWith($"{TableType.Para}$") || item.Key.StartsWith($"{TableType.Args}$"))
                {
                    continue;
                }
                else if (item.Key == TableType.Root.ToString())
                {
                    AnalysisRoot(item.Value);
                    continue;
                }

                string tbName = item.Key;
                DataTable dt = item.Value;

                dynamic[] datas = AnalysisDataTable(dt);
                _dynamicTable.Add(tbName, datas);
            }
        }

        /// <summary>
        /// 生成Json
        /// </summary>
        private void SaveToJson(string filePath)
        {
            if (_dynamicTable.ContainsKey(TableType.Array.ToString()))
            {
                root = _dynamicTable[TableType.Array.ToString()];
                JsonHelper.Save(root, filePath);
                return;
            }
            if (root == null)
            {
                root = new ExpandoObject();
            }
            _dynamicTable.ToList().ForEach(m => CommonHelper.AddProperty(root, m.Key, m.Value.ToArray()));
            JsonHelper.Save(root, filePath);
        }

        /// <summary>
        /// 解析根节点
        /// </summary>
        /// <param name="dt"></param>
        private void AnalysisRoot(DataTable dt)
        {
            var columns = CommonHelper.GetExcelColumns(dt);
            DataRow row = dt.Rows[0];
            AnalysisRow(row, columns, out root);
        }

        /// <summary>
        /// 解析表格
        /// </summary>
        /// <param name="dt"></param>
        /// <returns></returns>
        private dynamic[] AnalysisDataTable(DataTable dt)
        {
            var columns = CommonHelper.GetExcelColumns(dt);
            List<dynamic> datas = new List<dynamic>();

            foreach (DataRow row in dt.Rows)
            {
                AnalysisRow(row, columns, out dynamic data);
                datas.Add(data);
            }
            return datas.ToArray();
        }

        /// <summary>
        /// 解析《Para》类型表格
        /// </summary>
        /// <param name="para"></param>
        /// <returns></returns>
        private object? AnalysisPara(string para)
        {
            if (_dtList != null && _dtList.ContainsKey(para))
            {
                DataTable dt = _dtList[para];
                return AnalysisDataTable(dt);
            }
            return null;
        }

        /// <summary>
        /// 解析《Args》类型表格
        /// </summary>
        /// <param name="para"></param>
        /// <returns></returns>
        private object? AnalysisArgs(string para)
        {
            if (_dtList != null && _dtList.ContainsKey(para))
            {
                DataTable dt = _dtList[para];
                DataColumnCollection colums = dt.Columns;

                if (colums.Contains(Constants.ArgParameter) && colums.Contains(Constants.ArgType))
                {
                    List<object> args = new List<object>();
                    foreach (DataRow row in dt.Rows)
                    {
                        DataType dType = CommonHelper.GetEnumByDescription<DataType>(row[Constants.ArgType]?.ToString() ?? string.Empty);
                        string parameter = row[Constants.ArgParameter]?.ToString() ?? string.Empty;
                        args.Add(CommonHelper.ConvertValue(parameter, dType));
                    }
                    return args.ToArray();
                }
            }
            return null;
        }

        /// <summary>
        /// 解析表格行
        /// </summary>
        /// <param name="row"></param>
        /// <param name="columns"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        private object AnalysisRow(DataRow row, List<string> columns, out dynamic data)
        {
            data = new ExpandoObject();
            foreach (var column in columns)
            {
                var id = row[column]?.ToString() ?? string.Empty;
                var pName = CommonHelper.GetPropertyName(column);
                var pType = CommonHelper.GetPropertyType(column);

                object? args = CommonHelper.ConvertValue(id, DataType.String);
                if (!string.IsNullOrEmpty(pType))
                {
                    if (pType == TableType.Para.ToString())
                    {
                        var tp = CommonHelper.GetArgumentType(id);
                        if (!string.IsNullOrEmpty(tp) && tp == TableType.Para.ToString())
                        {
                            args = AnalysisPara(id);
                        }
                        else if (!string.IsNullOrEmpty(tp) && tp == TableType.Args.ToString())
                        {
                            args = AnalysisArgs(id);
                        }
                    }
                    else if (pType == DataType.String.ToString())
                    {
                        args = CommonHelper.ConvertValue(id, DataType.String);
                    }
                    else if (pType == DataType.Integer.ToString())
                    {
                        args = CommonHelper.ConvertValue(id, DataType.Integer);
                    }
                    else if (pType == DataType.Bool.ToString())
                    {
                        args = CommonHelper.ConvertValue(id, DataType.Bool);
                    }
                }
                CommonHelper.AddProperty(data, pName, args);
            }
            return data;
        }
    }
}
